Introduction

Motivation: Can I quantify the impact of the JP Morgan Healthcare Conference on healthcare stock value? Can I move beyond the truism that stocks change in response to the speeches, deals, and data presented at the meeting and describe the impact in detail? I’ve found some sources that attempt to quantify the impact of the meeting on stocks (see below).

Previous work

Here is an example of a quantification of impact of JPM week on biotech stocks:
[https://www.cnbc.com/2017/01/04/betting-on-biotech-during-jpmorgans-big-health-care-conference-pays-off-history-shows.html]
Quotes:

  • “Biotech has historically outperformed the broader market during The J.P. Morgan Healthcare Conference”
  • “In the past 16 years, the NYSE Arca Biotechnology index (BTK), which measures the performance of 30 biotechnology firms, has outperformed the S&P 500 index by nearly 3 percent during JPMorgan’s conference”

Based on these previous insights I hypothesize that:

  1. Healthcare stock prices tend to fluctuate more during JPM week than any other week in the same year.
  2. The biotech sector outperforms the S&P 500 during JPM week more often than is expected by chance.

Data import

Data required:

  • Daily stock prices (avg price and range) biotechs
  • JPM week dates back to inception of meeting
  • S&P 500 weekly performance

Import a list of biotech/pharma/healthcare tickers from the NASDAQ and NYSE.

## Parsed with column specification:
## cols(
##   Symbol = col_character(),
##   Name = col_character(),
##   Industry = col_character()
## )

Import stock data for these biotechs

## Parsed with column specification:
## cols(
##   price.open = col_double(),
##   price.high = col_double(),
##   price.low = col_double(),
##   price.close = col_double(),
##   volume = col_double(),
##   price.adjusted = col_double(),
##   ref.date = col_date(format = ""),
##   ticker = col_character(),
##   ret.adjusted.prices = col_double(),
##   ret.closing.prices = col_double()
## )

Import S&P 500 value using

S&P Index ticker is SPY and began in January 29, 1993.

## [1] "1993-01-29" "2019-05-24"

Also, it looks like I can download this as timeseries data (“ts”) getSymbols(‘F’,src=‘yahoo’,return.class=‘ts’)

Import NYSE Biotech index

NYSE Arca Biotechnology index (BTK), stated in January 2003.

## 'getSymbols' currently uses auto.assign=TRUE by default, but will
## use auto.assign=FALSE in 0.5-0. You will still be able to use
## 'loadSymbols' to automatically load data. getOption("getSymbols.env")
## and getOption("getSymbols.auto.assign") will still be checked for
## alternate defaults.
## 
## This message is shown once per session and may be disabled by setting 
## options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
## 
## WARNING: There have been significant changes to Yahoo Finance data.
## Please see the Warning section of '?getSymbols.yahoo' for details.
## 
## This message is shown once per session and may be disabled by setting
## options("getSymbols.yahoo.warning"=FALSE).
## Warning: BTK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## [1] "2003-01-03" "2019-06-03"

Import Biotech index value

NASDAQ Biotechnology index: NBI, started in November 2003.

## [1] "2003-12-12" "2019-05-24"

Import JPM week dates

I couldn’t find a website where is listed the JPM weeks over the history of the conference. Based on some searches of the previous names of the conference (Hambrecht & Quist Healthcare Conference, Chase H & Q, now JP Morgan) it seems like it’s always early January:

So I picked likely start dates in each year and then filled in the dates for the rest of the week.
##   [1] "1983-01-09" "1984-01-08" "1985-01-06" "1986-01-05" "1987-01-11"
##   [6] "1988-01-10" "1989-01-08" "1990-01-07" "1991-01-06" "1992-01-05"
##  [11] "1993-01-10" "1994-01-09" "1995-01-08" "1996-01-07" "1997-01-05"
##  [16] "1998-01-11" "1999-01-10" "2000-01-09" "2001-01-07" "2002-01-06"
##  [21] "2003-01-05" "2004-01-11" "2005-01-09" "2006-01-08" "2007-01-07"
##  [26] "2008-01-06" "2009-01-11" "2010-01-10" "2011-01-09" "2012-01-08"
##  [31] "2013-01-06" "2014-01-05" "2015-01-11" "2016-01-10" "2017-01-08"
##  [36] "2018-01-07" "1983-01-10" "1984-01-09" "1985-01-07" "1986-01-06"
##  [41] "1987-01-12" "1988-01-11" "1989-01-09" "1990-01-08" "1991-01-07"
##  [46] "1992-01-06" "1993-01-11" "1994-01-10" "1995-01-09" "1996-01-08"
##  [51] "1997-01-06" "1998-01-12" "1999-01-11" "2000-01-10" "2001-01-08"
##  [56] "2002-01-07" "2003-01-06" "2004-01-12" "2005-01-10" "2006-01-09"
##  [61] "2007-01-08" "2008-01-07" "2009-01-12" "2010-01-11" "2011-01-10"
##  [66] "2012-01-09" "2013-01-07" "2014-01-06" "2015-01-12" "2016-01-11"
##  [71] "2017-01-09" "2018-01-08" "1983-01-11" "1984-01-10" "1985-01-08"
##  [76] "1986-01-07" "1987-01-13" "1988-01-12" "1989-01-10" "1990-01-09"
##  [81] "1991-01-08" "1992-01-07" "1993-01-12" "1994-01-11" "1995-01-10"
##  [86] "1996-01-09" "1997-01-07" "1998-01-13" "1999-01-12" "2000-01-11"
##  [91] "2001-01-09" "2002-01-08" "2003-01-07" "2004-01-13" "2005-01-11"
##  [96] "2006-01-10" "2007-01-09" "2008-01-08" "2009-01-13" "2010-01-12"
## [101] "2011-01-11" "2012-01-10" "2013-01-08" "2014-01-07" "2015-01-13"
## [106] "2016-01-12" "2017-01-10" "2018-01-09" "1983-01-12" "1984-01-11"
## [111] "1985-01-09" "1986-01-08" "1987-01-14" "1988-01-13" "1989-01-11"
## [116] "1990-01-10" "1991-01-09" "1992-01-08" "1993-01-13" "1994-01-12"
## [121] "1995-01-11" "1996-01-10" "1997-01-08" "1998-01-14" "1999-01-13"
## [126] "2000-01-12" "2001-01-10" "2002-01-09" "2003-01-08" "2004-01-14"
## [131] "2005-01-12" "2006-01-11" "2007-01-10" "2008-01-09" "2009-01-14"
## [136] "2010-01-13" "2011-01-12" "2012-01-11" "2013-01-09" "2014-01-08"
## [141] "2015-01-14" "2016-01-13" "2017-01-11" "2018-01-10" "1983-01-13"
## [146] "1984-01-12" "1985-01-10" "1986-01-09" "1987-01-15" "1988-01-14"
## [151] "1989-01-12" "1990-01-11" "1991-01-10" "1992-01-09" "1993-01-14"
## [156] "1994-01-13" "1995-01-12" "1996-01-11" "1997-01-09" "1998-01-15"
## [161] "1999-01-14" "2000-01-13" "2001-01-11" "2002-01-10" "2003-01-09"
## [166] "2004-01-15" "2005-01-13" "2006-01-12" "2007-01-11" "2008-01-10"
## [171] "2009-01-15" "2010-01-14" "2011-01-13" "2012-01-12" "2013-01-10"
## [176] "2014-01-09" "2015-01-15" "2016-01-14" "2017-01-12" "2018-01-11"

Analysis

Cleaning the data, some thoughts:

  • I removed stock prices that are unbelievable high. I found that “The most expensive publicly traded stock of all time is Warren Buffett’s Berkshire Hathaway (BRK.A), which is trading at $305,500 per share, as of Oct. 23, 2018))” [https://www.investopedia.com/ask/answers/…/whats-most-expensive-stock-all-time.asp_] so I removed any prices that are higher than this value.
  • I (above) removed companies duplicated between NYSE/NASDAQ. Were these duplications due to companies switching exhanges? Other issues?
  • Other cleaning I could do: check that low prices are always < high prices, check for missing data, etc…
  • A point on missing data: the BatchGetSymbols function does a lot to replace missing data with most recent prices. I could look into the impact of this default parameter on my analysis at a later time.
## [1] 2014281      10
## [1] 1991750      10

Looks like we got rid of some bad data. Plot some price.high by company over the dates.
Looks good. These plots show that BatchGetSymbols() was able to handle companies as the entered and exited the stock market (unlike getSymbols()).

ggplot(SP500_index_daily_stocks, aes(x = ref.date, y = price.close)) + 
  geom_line() + 
  facet_wrap(~ticker, scales = 'free_y') 

ggplot(biotech_index_daily_stocks, aes(x = ref.date, y = price.close)) + 
  geom_line() + 
  facet_wrap(~ticker, scales = 'free_y') 

ggplot(BTK_index_daily_stocks, aes(x = ref.date, y = price.close)) + 
  geom_line() + 
  facet_wrap(~ticker, scales = 'free_y') 

Given how spotty the data is prior to 2010, let’s just use NBI 2010 and later:

## [1] 3888    8
## [1] 2364    8

Dropped a bunch of useless rows. Woo. Plot again:

## quartz_off_screen 
##                 2

Calculate stock price fluctuations

I’m using the word “fluctuations” here because I don’t have the technical expertise in finance to use a word like “volatility” which has a couple of specific definitions in finance. By “fluctuations” I mean that I’ll calculate the range in price for each stock each week of the year, then I’ll compare that range to the range over JPM week. This output will be a relative price range.

Calculate max net change (range) in price per day.
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##     0.00     0.19     0.50    40.87     1.31 86100.00
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    0.00    0.00    8.86   15.79   54.30
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##       0       0       0       0       0       0
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0937  0.8800  1.2400  1.6385  2.3376  6.4800
Calculate max price and min price each JPM week (by year) and list as the price_range.
Calculate difference in the price range of all subsequent weeks in the year.
Note, for simplicity here I’m not calculating each week of the year as M-F trading days, I’m using weeks based on date only (not day of week). I’m collecting data for each week starting on January 21st (week >= 3), where weeks are 7 day periods until the end of the year.

Compare all other weeks to JPM week.
I’ll start with just 2017 and ticker == ABBV to simplify things, then build back up to all tickers and years. ABBV is “AbbVie is an American publicly traded biopharmaceutical company founded in 2013. It originated as a spin-off of Abbott Laboratories.” [https://en.wikipedia.org/wiki/AbbVie_Inc.]

##  [1] 0.2598031 0.5833335 0.5024507 0.2377452 0.4730390 0.2303928 0.4705875
##  [8] 0.8749986 0.3651954 0.2622548 0.2769599 0.3137248 0.6029406 0.4534316
## [15] 0.7941168 0.3578430 0.5612725 0.5661755 0.4338226 0.4166657 0.7230401
## [22] 0.4583338 0.6691163 0.3995089 0.3872532 0.4730390 0.8063724 1.3161766
## [29] 0.3774510 0.4411770 0.4460782 0.7034298 0.8431373 2.7843106 1.3014712
## [36] 0.6691163 1.9019586 0.5931365 0.7132359 1.8872550 2.6372541 1.0857818
## [43] 1.2132359 0.6617636 0.6151965 1.0343117 0.9362738 1.0073527 0.4607834
## [50] 0.4215687

From this one example, we can see that the JPM week price range difference was not always greater than any other week of the year, but it was in the top 20% of weeks (10 points above red line implies 10 weeks had a price range >1x JPM week price range).
Are there any years for ABBV for which the JPM week price range was the maximal range for the year?

##          3     4     5     6     7    8    9   10   11    12   13    14
## 2013 FALSE FALSE  TRUE  TRUE FALSE TRUE TRUE TRUE TRUE  TRUE TRUE  TRUE
## 2014  TRUE FALSE FALSE FALSE  TRUE TRUE TRUE TRUE TRUE FALSE TRUE FALSE
## 2015  TRUE  TRUE FALSE  TRUE  TRUE TRUE TRUE TRUE TRUE  TRUE TRUE  TRUE
## 2016  TRUE  TRUE  TRUE  TRUE  TRUE TRUE TRUE TRUE TRUE  TRUE TRUE  TRUE
## 2017  TRUE  TRUE  TRUE  TRUE  TRUE TRUE TRUE TRUE TRUE  TRUE TRUE  TRUE
##         15    16    17    18   19    20    21    22    23    24    25
## 2013 FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE  TRUE FALSE FALSE
## 2014 FALSE  TRUE  TRUE  TRUE TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE
## 2015  TRUE  TRUE  TRUE  TRUE TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## 2016  TRUE  TRUE  TRUE  TRUE TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## 2017  TRUE  TRUE  TRUE  TRUE TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##         26   27    28    29    30   31   32    33    34   35    36    37
## 2013 FALSE TRUE  TRUE  TRUE  TRUE TRUE TRUE FALSE  TRUE TRUE FALSE  TRUE
## 2014 FALSE TRUE FALSE FALSE  TRUE TRUE TRUE  TRUE  TRUE TRUE  TRUE  TRUE
## 2015  TRUE TRUE  TRUE  TRUE  TRUE TRUE TRUE  TRUE FALSE TRUE  TRUE  TRUE
## 2016  TRUE TRUE  TRUE  TRUE  TRUE TRUE TRUE  TRUE  TRUE TRUE  TRUE  TRUE
## 2017  TRUE TRUE  TRUE  TRUE FALSE TRUE TRUE  TRUE  TRUE TRUE FALSE FALSE
##         38    39    40    41    42    43    44    45    46    47    48
## 2013 FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE  TRUE
## 2014 FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
## 2015  TRUE FALSE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE
## 2016  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
## 2017  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE
##         49    50    51   52   53
## 2013 FALSE FALSE FALSE TRUE TRUE
## 2014 FALSE FALSE FALSE TRUE TRUE
## 2015  TRUE  TRUE  TRUE TRUE TRUE
## 2016  TRUE  TRUE  TRUE TRUE TRUE
## 2017  TRUE FALSE  TRUE TRUE   NA

No, not quite. It was nearly the case in 2016.

Now, let’s extend this type of analysis to more tickers and also include a better summary visualization. I’ll create a table with years as rows, and then each ticker will be a column with the # weeks price range smaller than JPM week price range. We’ll be able to overlay all of these different tickers on the graph and we’ll look for trends.

The data is in “Wide” form right now, which is not very tidy! I’ll reshape into “Long” form for ease of compatibility with ggplot()

There are some zero values in this table that should really be NAs, so I’ll correct that now.

Plot the summary figure.
Yikes, that’s ugly and hard to interpret. Let’s try again.

Let’s change week per year to a percentage of weeks to ease interpretation.

Plot percentages.

## quartz_off_screen 
##                 2

Performance vs S&P 500

Let’s define performance as % increase from start to end of JPMHC week.

Change abline from no change to average weekly change that year.

Grey line is the average price change from Price.open at the beginning of the week to price.close at the end of the week for all weeks in the year after JPM.

Hypothesis 2: 2. The biotech sector outperforms the S&P 500 during JPM week more often than is expected by chance.

S&P500 vs Biotech Index stock

Will need to limit analysis to 2010-2018 because those are the dates for which I have full years of both the biotech and s&P500 index information.

Calculate an empirical pvalue for each year: JPMHC week ratio >= other week ratios + 1 / # other weeks + 1 (JPM week)

## Warning: `as_tibble.matrix()` requires a matrix with column names or a `.name_repair` argument. Using compatibility `.name_repair`.
## This warning is displayed once per session.
## [1] TRUE
## [1] 429
## [1] 457
## [1] "2018-11-15"
## [1] "2018-11-16"
## [1] 1

## [1]  0.1303458  1.7506577 -0.8433294  3.1958573  1.6270782 -0.1557898
## [7] -1.7675502  2.6744578
## [1] 11

## [1] 24

## [1] 6

## [1] 9

## [1] 4

## [1] 28

## [1] 17

## [1] 43

## [1] 9

## [1] 0.21153846 0.47058824 0.11538462 0.17307692 0.07692308 0.53846154
## [7] 0.32692308 0.84313725 0.17307692
## [1] 20

## [1] 8

## [1] 39

## [1] 4

## [1] 8

## [1] 22

## [1] 3

## [1] 0.39215686 0.16000000 0.78000000 0.09302326 0.21052632 0.42307692
## [7] 0.05769231
plot(c(2010, 2012:2016, 2018), BTK_pvals, ylim = c(0, 1), ylab = "P-value", xlab = "Date", pch = 19, main = "Biotech indices and S&P500 index stocks perform comparably\nduring JPMHC week vs later weeks in same year")
abline(h = 0.05, col = "red")
points(2010:2018, pvals, ylim = c(0, 1), ylab = "P-value", xlab = "Date", pch = 19, main = "NBI index and S&P500 index stocks perform comparably\nduring JPMHC week vs later weeks in the year", col = "blue")
legend("topright", legend = c("NYSE", "NASDAQ"), col = c("black", "blue"), pch = 19)

## quartz_off_screen 
##                 2
## quartz_off_screen 
##                 2

Done! Let’s interpret this data in light of my original hypotheses:

  1. Healthcare stock prices tend to fluctuate more during JPM week than any other week in the same year.
    This effect is only seen in the last 10 years. Perhaps the conference is becoming more influential with time?
  2. The biotech sector outperforms the S&P 500 during JPM week more often than is expected by chance.
    This is not reflected in my analyses. I found that using two different biotech index stocks, the ratio of the change in biotech index stock value to S&P500 index from the beginning to the end of JPMHC week is not statistically different from other weeks in the year. This finding is contradictory to my gut intuition and to other analyses.

What is might complicate the interpretation of the data:

  • Beginning of a fiscal quarter? Control by look at other quarters?
  • Every four years January means a new presidential term? Control by comparing years with and without inaugurations?
  • The choice to use individual stocks (unweighted) in flucation analysis vs index stocks (with weighting) in performance analysis.
  • Appropriate definition/calculation of fluctuation and performance.
  • Not having a completely accurate list of JPMHC dates.

Sources:

Helpful introductory tutorial to stock data in R by Curtis Miller: https://ntguardian.wordpress.com/2017/03/27/introduction-stock-market-data-r-1/

Example of how GetBatchSymbols works and improves upon quantmod library by Marcelo Perlin: https://cran.r-project.org/web/packages/BatchGetSymbols/vignettes/BatchGetSymbols-vignette.html